package com.codebo.homiematchbackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codebo.homiematchbackend.common.ErrorCode;
import com.codebo.homiematchbackend.exception.ThrowUtils;
import com.codebo.homiematchbackend.mapper.BlogMapper;
import com.codebo.homiematchbackend.model.dto.blog.*;
import com.codebo.homiematchbackend.model.entity.User;
import com.codebo.homiematchbackend.model.entity.blog.Blog;
import com.codebo.homiematchbackend.model.entity.blog.BlogCollect;
import com.codebo.homiematchbackend.model.entity.blog.BlogComment;
import com.codebo.homiematchbackend.model.entity.blog.BlogLike;
import com.codebo.homiematchbackend.model.vo.BlogVO;
import com.codebo.homiematchbackend.service.*;
import com.codebo.homiematchbackend.utils.SelfUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author 25912
 * @description 针对表【blog(博客)】的数据库操作Service实现
 * @createDate 2025-09-21 13:57:25
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog>
        implements BlogService
{

    @Resource
    private UserService userService;

    @Resource
    private BlogLikeService blogLikeService;

    @Resource
    private BlogCollectService blogCollectService;

    @Resource
    private BlogCommentService blogCommentService;

    @Resource
    private SelfUtil selfUtil;
    @Autowired
    private ServletRequest httpServletRequest;

    @Override
    @Transactional
    public long addBlog(BlogAddRequest blogAddREquest)
    {
        String title = blogAddREquest.getTitle();
        List<String> tags = blogAddREquest.getTags();
        String content = blogAddREquest.getContent();
        Long userId = blogAddREquest.getUserId();
        //判断参数
        ThrowUtils.throwIf(title.isEmpty() || title.length() > 30, ErrorCode.PARAMS_ERROR, "标题长度为1-30");
        ThrowUtils.throwIf(tags.size() > 5, ErrorCode.PARAMS_ERROR, "标签个数不能大于5");
        ThrowUtils.throwIf(content.isEmpty() || content.length() > 30000, ErrorCode.PARAMS_ERROR, "内容长度为1-30000");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");
        ThrowUtils.throwIf(userService.getById(userId) == null, ErrorCode.PARAMS_ERROR, "用户不存在");

        //存入数据库
        Blog blog = new Blog();
        BeanUtil.copyProperties(blogAddREquest, blog);
        blog.setTags(JSONUtil.toJsonStr(tags));
        boolean save = save(blog);
        //将用户的博客数量+1
        User user = userService.getById(userId);
        user.setBlogCount(user.getBlogCount() + 1);
        boolean update = userService.update().eq("id", userId).update(user);
        ThrowUtils.throwIf(!(save && update), ErrorCode.SYSTEM_ERROR, "创建博客失败");
        return blog.getId();
    }


    /**
     * 根据当前登录用户，返回最相似的博客分页
     * 匹配字段及权重：
     *   1. 用户简介 vs 博客标题+正文  权重 1
     *   2. 用户标签 vs 博客标签       权重 3
     *   3. 我能教/我想学 vs 博客正文  权重 4
     */
    /**
     * 随机取 50 篇博客，按与当前登录用户的相似度排序后返回前 10 篇
     */
    @Override
    public List<BlogVO> listBlogByRecommend(HttpServletRequest request, BlogQueryRequest blogQueryRequest)
    {
        // 1. 当前登录用户
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);

        // 2. 随机 50 条
        QueryWrapper<Blog> queryWrapper = this.getQueryWrapper(blogQueryRequest);
        queryWrapper.getExpression().getOrderBy().clear();
        queryWrapper.ne("user_id", loginUser.getId())//排除自己的博客
                .last("ORDER BY RAND() LIMIT 50");
        List<Blog> candidates = this.list(queryWrapper);

//        List<Blog> candidates = this.lambdaQuery()
//                .eq(Blog::getIsDelete, 0)
//                .last("ORDER BY RAND() LIMIT 50")
//                .list();
        if (CollUtil.isEmpty(candidates))
        {
            return Collections.emptyList();
        }

        // 3. 并行计算加权编辑距离
        Map<Blog, Integer> distanceMap = new ConcurrentHashMap<>(candidates.size());
        candidates.parallelStream().forEach(b ->
        {
            int d = 0;
            String titleContent = (b.getTitle() == null ? "" : b.getTitle())
                    + " " + (b.getContent() == null ? "" : b.getContent());
            d += 1 * selfUtil.editDistance(loginUser.getUserProfile(), titleContent);
            d += 3 * selfUtil.editDistance(loginUser.getUserTags(), b.getTags());
            d += 4 * selfUtil.editDistance(loginUser.getTeach(), b.getContent());
            d += 4 * selfUtil.editDistance(loginUser.getLearn(), b.getContent());
            distanceMap.put(b, d);
        });

        // 4. 排序并取前 10
        return candidates.stream()
                .sorted(Comparator.comparingInt(distanceMap::get))
                .limit(9)                       // 只保留 Top10
                .map(blog -> this.getBlogVO(blog, request))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean likeBlog(LikeBlogRequest likeBlogRequest)
    {
        //判断参数
        Long blogId = likeBlogRequest.getBlogId();
        Long userId = likeBlogRequest.getUserId();
        Boolean isLike = likeBlogRequest.getIsLiked();
        ThrowUtils.throwIf(blogId == null || blogId <= 0, ErrorCode.PARAMS_ERROR, "博客id不合法");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");
        ThrowUtils.throwIf(isLike == null, ErrorCode.PARAMS_ERROR, "点赞状态不合法");
        //存入数据库
        //存入blog_like表
        BlogLike blogLike = new BlogLike();
        BeanUtil.copyProperties(likeBlogRequest, blogLike);
        //判断是点赞还是取消点赞
        boolean saveBlogLike = false;
        boolean updateBlog = false;
        boolean updateUser = false;
        UpdateWrapper<Blog> blogUpdateWrapper = new UpdateWrapper<>();
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        QueryWrapper<BlogLike> queryWrapper = new QueryWrapper<>();
        BlogLike getOne = blogLikeService.getOne(queryWrapper.eq("user_id", userId).eq("blog_id", blogId));
        if (isLike)
        {
            ThrowUtils.throwIf(getOne != null,
                    ErrorCode.NOT_FOUND_ERROR, "您已经点赞过了");
            saveBlogLike = blogLikeService.save(blogLike);
            blogUpdateWrapper.eq("id", blogId)
                    .setSql("like_num = like_num + 1");
            userUpdateWrapper.eq("id", userId)
                    .setSql("like_count = like_count + 1");
        } else
        {
            ThrowUtils.throwIf(getOne == null,
                    ErrorCode.NOT_FOUND_ERROR, "您还没有点赞过");
            saveBlogLike = blogLikeService.removeById(getOne);
            blogUpdateWrapper.eq("id", blogId)
                    .setSql("like_num = like_num - 1");
            userUpdateWrapper.eq("id", userId)
                    .setSql("like_count = like_count - 1");
        }

        updateBlog = update(blogUpdateWrapper);
        updateUser = userService.update(userUpdateWrapper);

        return saveBlogLike && updateBlog && updateUser;
    }

    @Override
    @Transactional
    public boolean collectBlog(CollectBlogRequest collectBlogRequest)
    {
        //判断参数
        Long blogId = collectBlogRequest.getBlogId();
        Long userId = collectBlogRequest.getUserId();
        Boolean isCollect = collectBlogRequest.getIsCollected();
        ThrowUtils.throwIf(blogId == null || blogId <= 0, ErrorCode.PARAMS_ERROR, "博客id不合法");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");
        //存入数据库
        //存入blog_like表
        BlogCollect blogCollect = new BlogCollect();
        BeanUtil.copyProperties(collectBlogRequest, blogCollect);
        //判断是点赞还是取消点赞
        boolean saveBlogLike = false;
        boolean updateBlog = false;
        boolean updateUser = false;
        UpdateWrapper<Blog> blogUpdateWrapper = new UpdateWrapper<>();
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        QueryWrapper<BlogCollect> queryWrapper = new QueryWrapper<>();
        BlogCollect getOne = blogCollectService.getOne(queryWrapper.eq("user_id", userId).eq("blog_id", blogId));
        if (isCollect)
        {
            ThrowUtils.throwIf(getOne != null,
                    ErrorCode.NOT_FOUND_ERROR, "您已经点赞过了");
            saveBlogLike = blogCollectService.save(blogCollect);
            blogUpdateWrapper.eq("id", blogId)
                    .setSql("collect_num = collect_num + 1");
            userUpdateWrapper.eq("id", userId)
                    .setSql("collect_count = collect_count + 1");
        } else
        {
            ThrowUtils.throwIf(getOne == null,
                    ErrorCode.NOT_FOUND_ERROR, "您还没有点赞过");
            saveBlogLike = blogCollectService.removeById(getOne);
            blogUpdateWrapper.eq("id", blogId)
                    .setSql("collect_num = collect_num - 1");
            userUpdateWrapper.eq("id", userId)
                    .setSql("collect_count = collect_count - 1");
        }

        updateBlog = update(blogUpdateWrapper);
        updateUser = userService.update(userUpdateWrapper);

        return saveBlogLike && updateBlog&& updateUser;
//        //存入数据库
//        //存入blog_collect表
//        BlogCollect blogCollect = new BlogCollect();
//        BeanUtil.copyProperties(collectBlogRequest, blogCollect);
//        boolean saveBlogCollect = blogCollectService.save(blogCollect);
//        //更新博客喜欢数
//        UpdateWrapper<Blog> blogUpdateWrapper = new UpdateWrapper<>();
//        blogUpdateWrapper.eq("id", blogId)
//                .setSql("collect_num = collect_num + 1");
//        boolean updateBlog = update(blogUpdateWrapper);
//        return saveBlogCollect && updateBlog;

    }

    @Override
    @Transactional
    public boolean commentBlog(CommentBlogRequest commentBlogRequest)
    {
        //判断参数
        Long blogId = commentBlogRequest.getBlogId();
        Long userId = commentBlogRequest.getUserId();
        String text = commentBlogRequest.getText();
        ThrowUtils.throwIf(blogId == null || blogId <= 0, ErrorCode.PARAMS_ERROR, "博客id不合法");
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR, "用户id不合法");
        ThrowUtils.throwIf(StrUtil.isBlank(text), ErrorCode.PARAMS_ERROR, "评论内容不能为空");
        //存入数据库
        //存入blog_comment表
        BlogComment blogcomment = new BlogComment();
        BeanUtil.copyProperties(commentBlogRequest, blogcomment);
        boolean saveBlogComment = blogCommentService.save(blogcomment);
        //更新博客评论数
        UpdateWrapper<Blog> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", blogId)
                .setSql("comment_count = comment_count + 1");
        boolean updateBlog = update(updateWrapper);
        return saveBlogComment && updateBlog;
    }

    @Override
    public List<BlogVO> getRecentBlog(Long id, HttpServletRequest httpServletRequest)
    {

        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", id)  // 按用户ID筛选
                .orderByDesc("create_time")  // 按创建时间降序排序
                .last("LIMIT 3");  // 限制返回3条记录

        List<Blog> listBlog = this.list(queryWrapper);
        return getBlogVOList(listBlog, httpServletRequest);
    }

    @Override
    public QueryWrapper<Blog> getQueryWrapper(BlogQueryRequest blogQueryRequest)
    {
        QueryWrapper<Blog> queryWrapper = new QueryWrapper<>();
        if (blogQueryRequest == null)
        {
            return queryWrapper;
        }

        Long id = blogQueryRequest.getId();
        String title = blogQueryRequest.getTitle();
        List<String> tags = blogQueryRequest.getTags();
        String content = blogQueryRequest.getContent();
        String searchText = blogQueryRequest.getSearchText();
        Integer likeNum = blogQueryRequest.getLikeNum();
        Integer collectNum = blogQueryRequest.getCollectNum();
        Long viewCount = blogQueryRequest.getViewCount();
        Long commentCount = blogQueryRequest.getCommentCount();
        Long userId = blogQueryRequest.getUserId();
        Date startTime = blogQueryRequest.getStartTime();
        Date endTime = blogQueryRequest.getEndTime();
        Date createTime = blogQueryRequest.getCreateTime();
        Date updateTime = blogQueryRequest.getUpdateTime();
        String sortField = blogQueryRequest.getSortField();
        String sortOrder = blogQueryRequest.getSortOrder();


        // 主键
        queryWrapper.eq(id != null, "id", blogQueryRequest.getId());
        // 标题模糊
        queryWrapper.like(StrUtil.isNotBlank(title), "title", blogQueryRequest.getTitle());
        // 内容模糊
        queryWrapper.like(StrUtil.isNotBlank(content), "content", blogQueryRequest.getContent());
        // 精确数值
        queryWrapper.eq(likeNum != null, "like_num", blogQueryRequest.getLikeNum());
        queryWrapper.eq(collectNum != null, "collect_num", blogQueryRequest.getCollectNum());
        queryWrapper.eq(viewCount != null, "view_count", blogQueryRequest.getViewCount());
        queryWrapper.eq(commentCount != null, "comment_count", blogQueryRequest.getCommentCount());
        // 用户
        queryWrapper.eq(userId != null, "user_id", blogQueryRequest.getUserId());
        // 时间范围（如果有）
        queryWrapper.ge(createTime != null, "create_time", blogQueryRequest.getCreateTime());
        queryWrapper.le(updateTime != null, "update_time", blogQueryRequest.getUpdateTime());

        // 全局搜索词：同时对标题、内容模糊
        if (StrUtil.isNotBlank(searchText))
        {
            queryWrapper.and(w -> w
                            .like("title", searchText)
                            .or()
                            .like("content", searchText)
                            .or()
                            .like("tags", searchText)
//                    .apply("JSON_SEARCH(tags, 'one', {0}) IS NOT NULL", searchText)
            );
        }

        // tags 是 List<String>，入库为 JSON 数组；按包含任意一条查询
        if (tags != null && !tags.isEmpty())
        {
            // 循环构造 JSON_CONTAINS
            queryWrapper.and(w ->
            {
                for (String tag : tags)
                {
                    w.or().apply("JSON_CONTAINS(tags, JSON_QUOTE({0}))", tag);
                }
            });
        }
        queryWrapper.lt(ObjUtil.isNotEmpty(endTime), "create_time", endTime);
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }

    @Override
    public BlogVO getBlogVO(Blog blog, HttpServletRequest httpServletRequest)
    {
        BlogVO blogVO = new BlogVO();
        BeanUtil.copyProperties(blog, blogVO);
        blogVO.setTags(JSONUtil.toList(blog.getTags(), String.class));
        blogVO.setUserVO(userService.getUserVO(userService.getById(blog.getUserId())));
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("blog_id", blog.getId());
        queryWrapper.eq("user_id", userService.getLoginUser(httpServletRequest).getId());
        BlogLike blogLike = blogLikeService.getOne(queryWrapper);
        blogVO.setIsLiked(blogLike != null);
        BlogCollect blogCollect = blogCollectService.getOne(queryWrapper);
        blogVO.setIsCollected(blogCollect != null);
        return blogVO;

    }

    @Override
    public List<BlogVO> getBlogVOList(List<Blog> blogs, HttpServletRequest httpServletRequest)
    {
        return blogs.stream().map(blog -> getBlogVO(blog, httpServletRequest)).collect(Collectors.toList());
    }
}




